package Element;

import java.awt.*;
import java.awt.geom.*;

import Element.Geom.*;
import DistSys.*;

public class DrtBreaker extends AbsElem implements Cloneable {
    public static AbsElem objActiveTemp;  //a developer's version of ActiveTemplate

    public DrtBreaker(){ }

    public Object clone(){
        DrtBreaker created = new DrtBreaker();
        this.copyTo(created); // copy AbsElem attributes to created
        //created.setDftTemp(this.getDftTempName());
        //created.rel  = (ReliaInd) (this.rel.clone());
        //created.ckt  = (CktLaw) (this.ckt.clone());
        created.geom = (SwtGeom) (((SwtGeom)this.geom).clone());
        return created;
    }

    public int getType() { return SysConst.TYPE_DRT_BREAKER; }

    public void draw(Graphics2D g2, double dist, double theta) {
        int x1 = geom.x1, y1 = geom.y1, x2 = geom.x2, y2 = geom.y2;

        int Ax = x1 + (int)(dist * Math.cos(theta)/3);
        int Ay = y1 + (int)(dist * Math.sin(theta)/3);
        int Bx = x1 + (int)(dist * Math.cos(theta)*2/3);
        int By = y1 + (int)(dist * Math.sin(theta)*2/3);
        int Cx = (Ax + Bx)/2;
        int Cy = (Ay + By)/2;

        int AAx = x1 + (int)(dist * Math.cos(theta)/12);
        int AAy = y1 + (int)(dist * Math.sin(theta)/12);
        int BBx = x1 + (int)(dist * Math.cos(theta)*11/12);
        int BBy = y1 + (int)(dist * Math.sin(theta)*11/12);

        g2.drawLine(x1,y1, AAx,AAy);     //don't rotate the handle line
        g2.drawLine(BBx,BBy, x2,y2);

        double length = Math.sqrt((double) ((Ax-Bx)*(Ax-Bx) + (Ay-By)*(Ay-By)));
        int tmp1 = (int) ((double)(Ax+Bx)/2.0 - length/2.0);
        int tmp2 = (int) ((double)(Ay+By)/2.0 - length/2.0);
        // don't use Cx - length/2 to avoid loss of precision

        if (!((SwtGeom)geom).getIsOpen() && getHasReclosingRelay()) {
            //add "R" and "x"; no need to transfor "R" and "x"
            //draw "R" and "x" inside of the circle
            int r = (int) (length/8.0);

            int Dx=Cx-r, Dy=Cy-2*r;
            int Ex=Cx-r, Ey=Cy+2*r;
            int Fx=Cx,   Fy=Cy-2*r;
            int Gx=Cx,   Gy=Cy;
            int Hx=Cx+r, Hy=Cy+2*r;
            int Mx=Cx-r, My=Cy;

            g2.drawLine(Dx,Dy, Ex,Ey);
            g2.drawLine(Dx,Dy, Fx,Fy);
            g2.drawLine(Mx,My, Gx,Gy);
            g2.drawArc(Dx,Dy, 2*r,2*r, -90,180);
            g2.drawLine(Gx,Gy, Hx,Hy);

            if (getIsInstantBlocked()) {
                int Ix=Cx+r,    Iy=Cy;
                int Jx=Cx+3*r,  Jy=Cy+2*r;
                int Kx=Cx+3*r,  Ky=Cy;
                int Lx=Cx+r,    Ly=Cy+2*r;

                g2.drawLine(Ix,Iy, Jx,Jy);     //draw "x"
                g2.drawLine(Kx,Ky, Lx,Ly);     //as the subscript
            }
        }

        int r = (int) (length / 4.0);
        int Dx=Cx-2*r, Dy=Cy-2*r;   //D = upperLeft of the square // not used here
        int Ex=Cx-5*r, Ey=Cy;       //E is point AA theoretically; re-calc E to avoid numerical error
        int Fx=Cx-4*r, Fy=Cy-2*r;
        int Gx=Cx-4*r, Gy=Cy+2*r;
        int Hx=Cx-4*r, Hy=Cy;
        int Ix=Cx-3*r, Iy=Cy-2*r;
        int Jx=Cx-3*r, Jy=Cy+2*r;

        int Kx=Cx+3*r, Ky=Cy-2*r;
        int Lx=Cx+3*r, Ly=Cy+2*r;
        int Mx=Cx+4*r, My=Cy;
        int Nx=Cx+4*r, Ny=Cy-2*r;
        int Ox=Cx+4*r, Oy=Cy+2*r;
        int Px=Cx+5*r, Py=Cy;       //P is point BB theoretically; re-calc P to avoid numerical error

        AffineTransform t = geom.t;
        t.setToRotation(theta, Cx, Cy);
        g2.transform(t);

        if (((SwtGeom)geom).getIsOpen()) {
            g2.fillRect(tmp1,tmp2, (int)length,(int)length);
        } else {
            g2.drawRect(tmp1,tmp2, (int)length,(int)length);
        }

        g2.drawLine(Hx,Hy, Cx-2*r,Cy);  // H--A
        g2.drawLine(Cx+2*r,Cy, Mx,My);  // B--M

        g2.drawLine(Ex,Ey, Fx,Fy);
        g2.drawLine(Ex,Ey, Gx,Gy);
        g2.drawLine(Hx,Hy, Ix,Iy);
        g2.drawLine(Hx,Hy, Jx,Jy);

        g2.drawLine(Mx,My, Kx,Ky);
        g2.drawLine(Mx,My, Lx,Ly);
        g2.drawLine(Px,Py, Nx,Ny);
        g2.drawLine(Px,Py, Ox,Oy);
    }

    /**
     * Returns whether the data field with the given index "makes sense" for
     * this element type or not.
     *
     * @param index  a <code>int</code> specifying the index.
     *
     * @return  <code>true</code> if the data field "makes sense",
     *          <code>false</code> otherwise
     */
    public boolean getDataExists(int index) {
        // A switch is used here to be independent of the
        // AbsElem.DATA_* constant's real values.
        switch(index) {
            case AbsElem.DATA_ZONE:
            case AbsElem.DATA_LAYER:
            case AbsElem.DATA_RATED_POWER:
            case AbsElem.DATA_RATED_CURR:
            case AbsElem.DATA_RECLOSING:
            case AbsElem.DATA_INST_BLOCKED:
            case AbsElem.DATA_ZONE_BUFFER0:
            case AbsElem.DATA_ZONE_BUFFER2:
            case AbsElem.DATA_ZONE_BUFFER4:
            case AbsElem.DATA_ZONE_BUFFER1:
            case AbsElem.DATA_ZONE_BUFFER3:
            case AbsElem.DATA_TEMP_FAULT:
            case AbsElem.DATA_SUST_FAULT:
            case AbsElem.DATA_OPEN_CKT:
            case AbsElem.DATA_MTTR:
            case AbsElem.DATA_MTTS:
            case AbsElem.DATA_OPER_FAIL:
            case AbsElem.DATA_VOLT_SAG_LEVEL:
            case AbsElem.DATA_RESISTANCE:
            case AbsElem.DATA_REACTANCE:
            case AbsElem.DATA_SHUNT_COND:
            case AbsElem.DATA_SHUNT_SUCEP:
            case AbsElem.DATA_CAPITAL_COST:
            case AbsElem.DATA_OM_COST:
            case AbsElem.DATA_FONT_SIZE:
            case AbsElem.DATA_IN_OPT_LIB:
            case AbsElem.DATA_MAINT_DUR:
            case AbsElem.DATA_MAINT_RATE:
            case AbsElem.DATA_NORM_OPEN:
            case AbsElem.DATA_OPTIMIZABLE:
            case AbsElem.DATA_PHASE:
            case AbsElem.DATA_STUDY_AREA:
            case AbsElem.DATA_UPGRADE_COST:
            case AbsElem.DATA_YEAR:
                return true;
            default:
                return false;
        }
    }

    /**
     * Returns whether the result field with the given index "makes sense" for
     * this element type or not.
     *
     * @param index  a <code>int</code> specifying the index.
     *
     * @return  <code>true</code> if the result field "makes sense",
     *          <code>false</code> otherwise
     */
    public boolean getResultExists(int index) {
        // A switch is used here to be independent of the
        // AbsElem.RES_* constant's real values.
        switch(index) {
            case AbsElem.RES_QUERY_SCORE:
            case AbsElem.RES_QUERY_SCORE_PERC:
            case AbsElem.RES_MOMENT_INT:
            case AbsElem.RES_SUST_INT:
            case AbsElem.RES_OUT_DUR:
            case AbsElem.RES_VOLT_SAGS:
            case AbsElem.RES_SWT_OPER:
            case AbsElem.RES_TRIP_OPER:
            case AbsElem.RES_RECLOSE_OPER:
            case AbsElem.RES_BLOCK_OPER:
            case AbsElem.RES_CAPA_CONS:
            case AbsElem.RES_CAPA_CONS_KVA:
            case AbsElem.RES_KVA_FLOW:
            case AbsElem.RES_PF:
            case AbsElem.RES_VOLT_MAG:
            case AbsElem.RES_VOLT_ANG:
            case AbsElem.RES_CURR_MAG:
            case AbsElem.RES_CURR_ANG:
            case AbsElem.RES_SHORTCIRC_CURR:
            case AbsElem.RES_VOLT_DROP:
            case AbsElem.RES_CURR_LOADING:
            case AbsElem.RES_KVA_RATING:
            case AbsElem.RES_MAIFI:
            case AbsElem.RES_SAG:
            case AbsElem.RES_SAIDI:
            case AbsElem.RES_SAIFI:
            case AbsElem.RES_VOLT_MAG_NODE1:
            case AbsElem.RES_VOLT_ANG_NODE1:
            case AbsElem.RES_VOLT_SAGS_ON_TGT:
            case AbsElem.RES_VOLT_SAGS_NODE1:
            case AbsElem.RES_PROTECT_ZONE:
            case AbsElem.RES_SA_MOMENT_INT:
            case AbsElem.RES_SA_SUST_INT:
            case AbsElem.RES_SA_DUR_SI:
            case AbsElem.RES_OLV_MI:
            case AbsElem.RES_OLV_SI:
            case AbsElem.RES_OLV_DUR_SI:
            case AbsElem.RES_UVV_MI:
            case AbsElem.RES_UVV_SI:
            case AbsElem.RES_UVV_DUR_SI:
                return true;
            default:
                return false;
        }
    }
}